package com.jt.demo2.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.boot.ansi.AnsiOutput;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect   //标识当前类是一个切面
public class TxAspect {
    //编码 ： 切面=切入点表达式 + 通知方法
    //切入点表达式：为谁创建代理对象
   // @Pointcut("bean(userServiceImpl)")  //标识切入点表达式
    //@Pointcut("within(com.jt.demo2.service.*)")多个
   // @Pointcut("execution(void com.jt.demo2.service.UserServiceImpl.addUser())")
   // @Pointcut("execution(* com.jt.demo2.service..*.*(..))")
    @Pointcut("@annotation(com.jt.demo2.anno.TX)")
    public void pointCut(){

    }
    //通知方法 对原来方法进行扩展
    @Before("pointCut()")   //通知注解
    public void before(JoinPoint joinPoint){
        //1、获取目标对象的类型
        Class targetClass = joinPoint.getTarget().getClass();
        //2、获取目标对象的名称
        String targetName = joinPoint.getSignature().getDeclaringTypeName();
        //3、获取目标方法的名称
        String methodName = joinPoint.getSignature().getName();
        //3、获取参数数据
        Object[] args = joinPoint.getArgs();

        System.out.println("目标对象类型;"+targetClass);
        System.out.println("目标对象名称;"+targetName);
        System.out.println("目标方法名称;"+methodName);
        System.out.println("参数名称;"+ Arrays.toString(args));
    }

    /**
     * 记录目标方法的返回值结果
     * returning：后置通知获取返回值的属性
     * @param result
     */
    @AfterReturning(value = "pointCut()",returning = "result")
    public void aferreturning(Object result){
        System.out.println("方法的返回值："+result);
    }

    /**
     * 说明：如果程序执行抛出异常，则可以由异常通知进行记录
     *       throwing :抛出异常的属性
     */
    @AfterThrowing(value = "pointCut()",throwing = "exception")
    public void afterThrowing(Exception exception){
        System.out.println("异常信息："+exception.getMessage());
    }

    @After("pointCut()")
    public void after(){
        System.out.println("AOP最终通知！！");
    }

    /**
     * 注意事项：环绕通知中必须添加参数，并且必须位于第一位
     * 用法：
     * 1、如果有下一个通知，则执行下一个通知，
     * 2、如果没有下一个通知则执行目标方法
     * @return
     */
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知开始");
        Object result = joinPoint.proceed();
        System.out.println("环绕通知结束");
        return result;
    }
}
